﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Windows;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Threading;
using Microsoft.Practices.ServiceLocation;
using SAFPodcast.WP8.DAL.FileSystem;
using SAFPodcast.WP8.DTO.Entities;
using SAFPodcast.WP8.DTO.TO;
using SAFPodcast.WP8.Fwk;
using SAFPodcast.WP8.Fwk.Cache;
using SAFPodcast.WP8.Fwk.Helper;
using SAFPodcast.WP8.Fwk.IO;
using SAFPodcast.WP8.Model.Services;

namespace SAFPodcast.WP8.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        #region Properties
        private readonly object syncLock = new object();
        private readonly IDataService _dataService;
        #endregion
        #region Constructeur
        public MainViewModel(IDataService dataService)
        {
            _dataService = dataService;
            PrepareBackgroundWork();
            InitializeValues();
            LoadData();
        }

        private void PrepareBackgroundWork()
        {
            ILockScreenManager manager = LockScreenManager.Instance;
            if (!manager.UserPrompted)
            {
                var allow = MessageBox.Show(
                    "Is it OK to run under the phone's lock screen?", "Authorization required", MessageBoxButton.OKCancel);
                manager.RunningUnderLockScreenEnabled = allow == MessageBoxResult.OK;
                manager.UserPrompted = true;
            }
            runningUnderLockScreenEnabled = manager.RunningUnderLockScreenEnabled;

            manager.PropertyChanged += (o, args) =>
                {
                    if (args.PropertyName == "RunningUnderLockScreen")
                    {
                        LogHelper.Debug("RunningUnderLockScreen: "
                                           + manager.RunningUnderLockScreen);
                    }
                };

        }

        private void InitializeValues()
        {
#if DEBUG
            //UrlPodcastAsString = "http://localhost/cairnomount_lo.mp3";
            UrlPodcastAsString = "http://www.api.europe1.fr/podcast/mp3/61/1732647/podcast.mp3";
#endif
            CompletionPodcast = 0;
            CanDownloadPodcast = true;
            IsDownloadingPodcast = false;
            editFeed = new RelayCommand<Feed>(EditFeedMethod);
            deleteFeed = new RelayCommand<Feed>(DeleteFeedMethod);
            downloadPodcast = new RelayCommand(DownloadPodcastMethod);
            addFeed = new RelayCommand(AddFeedMethod);
            Feeds = new ObservableCollection<Feed>();
            viewFeed = new RelayCommand<Feed>(ViewFeedMethod);
            sendErrors = new RelayCommand(SendErrorsMethod);
        }

        private void LoadData()
        {
            _dataService.GetFeeds((item, ex) =>
            {
                Feeds.Clear();
                foreach (var file in item.List)
                {
                    Feeds.Add(file);
                }
            });

        }
        #endregion

        #region IsDownloadingPodcast
        public const string IsDownloadingPodcastPropertyName = "IsDownloadingPodcast";
        private bool isDownloadingPodcast;
        public bool IsDownloadingPodcast
        {
            get { return isDownloadingPodcast; }
            set { Set(IsDownloadingPodcastPropertyName, ref isDownloadingPodcast, value); }
        }
        #endregion
        #region CanDownloadPodcast
        public const string CanDownloadPodcastPropertyName = "CanDownloadPodcast";
        private bool canDownloadPodcast;
        public bool CanDownloadPodcast
        {
            get { return canDownloadPodcast; }
            set { Set(CanDownloadPodcastPropertyName, ref canDownloadPodcast, value); }
        }
        #endregion
        #region CompletionPodcast
        public const string CompletionPodcastPropertyName = "CompletionPodcast";
        private int completionPodcast;
        public int CompletionPodcast
        {
            get { return completionPodcast; }
            set { Set(CompletionPodcastPropertyName, ref completionPodcast, value); }
        }
        #endregion
        #region UrlPodcastAsString
        public const string UrlPodcastAsStringPropertyName = "UrlPodcastAsString";
        private string urlPodcastAsString;
        public string UrlPodcastAsString
        {
            get { return urlPodcastAsString; }
            set { Set(UrlPodcastAsStringPropertyName, ref urlPodcastAsString, value); }
        }
        #endregion

        #region DownloadPodcast
        private RelayCommand downloadPodcast;
        public ICommand DownloadPodcast
        {
            get { return downloadPodcast; }
        }

        private void DownloadPodcastMethod()
        {
            if (CanDownloadPodcast)
            {
                lock (syncLock)
                {
                    if (CanDownloadPodcast)
                    {
                        IsDownloadingPodcast = false;
                        if (!String.IsNullOrWhiteSpace(UrlPodcastAsString))
                        {
                            Uri uri = null;
                            if (Uri.TryCreate(UrlPodcastAsString, UriKind.Absolute, out uri))
                            {
                                _dataService.DownloadPodcast(uri, DownloadPodcastMethodCallback);
                                CanDownloadPodcast = false;
                            }
                            else
                            {
                                MessageBox.Show("The URL is not valid.", "URL", MessageBoxButton.OK);
                            }
                        }
                    }
                }
            }
        }

        private void DownloadPodcastMethodCallback(DownloadDataItem dataItem, Exception ex)
        {
            if (ex == null)
            {
                if (dataItem.Canceled)
                {
                    CompletionPodcast = 0;
                    IsDownloadingPodcast = false;
                    CanDownloadPodcast = true;
                }
                else
                {
                    IsDownloadingPodcast = true;
                    CompletionPodcast = dataItem.Completion;
                    if (dataItem.Stream != null)
                    {
                        var copier = new FileCopier(
                            dataItem.Stream,
                            Path.Combine(Guid.NewGuid().ToString() + ".mp3"),
                            dataItem.Song,
                            (a) => DispatcherHelper.RunAsync(a),
                            FileSystemAccessObject.WriteFile);
                        copier.CopyCompleted += new FileCopier.CopyCompletedEventhandler(copier_CopyCompleted);
                        DispatcherHelper.RunAsync(copier.Run);
                    }
                }
            }
            else
            {
                LogHelper.Error("Erreur durant le téléchargement d'un podcast (callback)", ex);
                CanDownloadPodcast = true;
                IsDownloadingPodcast = false;
            }
        }

        void copier_CopyCompleted(object source, EventArgs e)
        {
            LoadData();
            CompletionPodcast = 0;
            IsDownloadingPodcast = false;
            CanDownloadPodcast = true;
        }
        #endregion

        #region Feeds
        public const string FeedsPropertyName = "Feeds";
        private ObservableCollection<Feed> feeds;
        public ObservableCollection<Feed> Feeds
        {
            get { return feeds; }
            set { Set(FeedsPropertyName, ref feeds, value); }
        }
        #endregion
        #region AddFeed
        private RelayCommand addFeed;
        public ICommand AddFeed
        {
            get { return addFeed; }
        }

        public void AddFeedMethod()
        {
            var vm = ServiceLocator.Current.GetInstance<AddFeedViewModel>();
#if!DEBUG
            vm.UrlAsString = String.Empty;
            vm.Name = String.Empty;
#endif
            this.MessengerInstance.Send(new Uri("/AddFeedView.xaml", UriKind.Relative), "NavigationRequest");
        }
        #endregion
        #region ViewFeed
        private RelayCommand<Feed> viewFeed;
        public RelayCommand<Feed> ViewFeed
        {
            get { return viewFeed; }
        }
        private void ViewFeedMethod(Feed value)
        {
            var idAsString = value.Id.ToString();
            var cache = ServiceLocator.Current.GetInstance<SimpleCache>();
            var viewVM = ServiceLocator.Current.GetInstance<ViewFeedViewModel>();
            List<FeedItem> items = null;

            if (cache.TryGet(idAsString, ref items))
            {
                items.ForEach(x => viewVM.FeedItems.Add(x));
            }
            else
            {
                viewVM.SelectedFeed = value;
                if (viewVM.FeedItems != null)
                {
                    viewVM.FeedItems.Clear();
                }
                else
                {
                    viewVM.FeedItems = new ObservableCollection<FeedItem>();
                }
                _dataService.LoadAndParseFeed(value,
                    (result, ex) =>
                    {
                        if (ex == null)
                        {
                            cache.Put(idAsString, result);
                            DispatcherHelper.RunAsync(() => result.ForEach(x => viewVM.FeedItems.Add(x)));
                        }
                        else
                        {
                            DispatcherHelper.RunAsync(() => MessageBox.Show("Can't download feed items", "Error", MessageBoxButton.OK));
                            this.MessengerInstance.Send(true, "NavigationBackRequest");
                        }
                    }
                );
            }
            this.MessengerInstance.Send(new Uri("/ViewFeedView.xaml", UriKind.Relative), "NavigationRequest");
        }
        #endregion
        #region EditFeed
        private RelayCommand<Feed> editFeed;
        public RelayCommand<Feed> EditFeed
        {
            get { return editFeed; }
        }

        public void EditFeedMethod(Feed feed)
        {
            var editVM = ServiceLocator.Current.GetInstance<EditFeedViewModel>();
            editVM.SelectedFeed = feed;
            editVM.Name = feed.Name;
            editVM.UrlAsString = feed.URI;
            this.MessengerInstance.Send(new Uri("/EditFeedView.xaml", UriKind.Relative), "NavigationRequest");
        }
        #endregion
        #region DeleteFeed
        private RelayCommand<Feed> deleteFeed;
        public RelayCommand<Feed> DeleteFeed
        {
            get { return deleteFeed; }
        }

        public void DeleteFeedMethod(Feed feed)
        {
            var result = MessageBox.Show("Do you want to deleted the podcast related to this feed?", "Delete", MessageBoxButton.OKCancel);
            if (result == MessageBoxResult.OK)
            {
                _dataService.DeleteFeed(feed);
                Feeds.Remove(feed);
            }
        }
        #endregion

        #region SendErrors
        private RelayCommand sendErrors;
        public ICommand SendErrors
        {
            get { return sendErrors; }
        }

        public void SendErrorsMethod()
        {
            _dataService.SendErrors();
        }
        #endregion

        #region RunningUnderLockScreenEnabled
        public const string RunningUnderLockScreenEnabledPropertyName = "RunningUnderLockScreenEnabled";
        private bool runningUnderLockScreenEnabled;
        public bool RunningUnderLockScreenEnabled
        {
            get { return runningUnderLockScreenEnabled; }
            set
            {
                var result = Set(RunningUnderLockScreenEnabledPropertyName, ref runningUnderLockScreenEnabled, value);
                if (result)
                {
                    LockScreenManager.Instance.RunningUnderLockScreenEnabled = runningUnderLockScreenEnabled;
                }
            }
        }
        #endregion
    }
}
